home *** CD-ROM | disk | FTP | other *** search
/ Developer Helper 1: Phil & Dave's Excellent CD / Excellent CD HFS.raw / Moof / Goodies / HyperCard Goodies / Serial Toolkit / Source Code / recvUpTo.p < prev    next >
Text File  |  1988-11-18  |  8KB  |  279 lines

  1. (*
  2.     recvUpTo(termination character, waitTime,oldString) -- Return a string from the
  3.         serial port; return everything available, up to the termination character (if any). Pass an empty
  4.         termination character to receive everything available. WaitTime is the amount of time to wait
  5.         for the input, in ticks (60ths of a second). oldString is what was read the last call (presumably
  6.         terminated due to a time-out).
  7.  
  8.     To compile and link this file using Macintosh Programmer's Workshop,
  9.  
  10.         pascal -w recvUpTo.p
  11.         link -m ENTRYPOINT -o HyperCommands -rt XFCN=7032 -sn Main=recvUpTo ∂
  12.             recvUpTo.p.o "{MPW}"Libraries:interface.o
  13.  
  14.     © Copyright 1987,88 by Apple Computer, Inc.
  15.  
  16.     Initial coding 9/87 by Harry R. Chesley.
  17. *)
  18.  
  19. {$R-}
  20.  
  21. {$S recvUpTo }     { Segment name must be the same as the command name. }
  22.  
  23. unit DummyUnit;
  24.  
  25. interface
  26.  
  27. uses MemTypes, QuickDraw, OSIntf, ToolIntf, HyperXCmd;
  28.  
  29. procedure EntryPoint(paramPtr: XCmdPtr);
  30.     
  31. implementation
  32.  
  33. const
  34.  
  35. return = 13;                { Carriage return. }
  36. linefeed = 10;            { Line feed. }
  37. bs = 8;                        { Back space. }
  38. delete = 127;            { Delete. }
  39. space = ord(' ');        { Space. }
  40. tab = 9;                    { Horizontal tab. }
  41.  
  42. type
  43.  
  44. Str31 = String[31];
  45.  
  46. procedure recvUpTo(paramPtr: XCmdPtr); forward;
  47.  
  48. procedure EntryPoint(paramPtr: XCmdPtr);
  49.  
  50.     begin
  51.         recvUpTo(paramPtr);
  52.     end;
  53.  
  54. procedure recvUpTo(paramPtr: XCmdPtr);
  55.  
  56.     var str: Str255;
  57.         l: longInt;
  58.         waitForChars: longInt;        { Ticks to wait until for characters (compated to TickCount). }
  59.         lookForTerm: boolean;        { True if we're looking for a terminator character. }
  60.         termChar: signedByte;        { The terminator character we're looking for. }
  61.         resultHand: Handle;            { A handle to the result string. }
  62.         resultSize: longInt;            { The size of the result string (minus the zero termination tacked on last). }
  63.         theChar: signedByte;
  64.         p, p2: Ptr;
  65.         col: integer;                        { The current column. }
  66.         i,j: integer;
  67.  
  68.     {$I XCmdGlue.inc}
  69.  
  70.     procedure Fail(errMsg: Str255); { set theResult and quit }
  71.         begin
  72.             paramPtr^.returnValue := PasToZero(errMsg);
  73.             exit(recvUpTo);
  74.         end;
  75.  
  76.     {$I SPortUtil.inc}
  77.  
  78.     procedure sendByte(b: SignedByte);
  79.         { Send one byte out the port. }
  80.  
  81.         var l: longInt;
  82.  
  83.         begin
  84.             l := 1;
  85.             if FSWrite(ThisSPort.portOutDev,l,@b) <> noErr then Fail('FSWrite failed');
  86.         end;
  87.  
  88.     procedure sendCRLF;
  89.         { Send a carriage return/linefeed out the port. }
  90.  
  91.         begin
  92.             sendByte(return); sendByte(linefeed);
  93.         end;
  94.  
  95.     procedure sendBS;
  96.         { Backspace on a terminal attached to the port: backspace, then space to erase any character in the
  97.             previous position, then backspace again to get the cursor in the right place. }
  98.  
  99.         begin
  100.             sendByte(bs); sendByte(space); sendByte(bs);
  101.         end;
  102.  
  103.     procedure disposAndFail(err: str255);
  104.         { Fail routine used after the result handle has been allocated. }
  105.  
  106.         begin
  107.             DisposHandle(resultHand);
  108.             Fail(err);
  109.         end;
  110.  
  111.     begin
  112.         if paramPtr^.paramCount <> 3 then Fail('parameter count is not 3');
  113.  
  114.         SetUpSPortGlobals;
  115.         EnsureOpenPort;
  116.  
  117.         GetStrParm(1,str);                                        { First parameter is termination character. }
  118.         if length(str) = 0 then lookForTerm := false
  119.         else
  120.             begin
  121.                 lookForTerm := true;
  122.                 termChar := SignedByte(str[1]);
  123.             end;
  124.         waitForChars := GetLongParm(2);                    { Second parameter is whether to wait. }
  125.         resultHand := paramPtr^.params[3];                { Third parameter is the old string. }
  126.  
  127.         { If there's anything in the "previous" string, copy it. }
  128.         if resultHand <> NIL then
  129.             begin
  130.                 p := resultHand^;
  131.                 resultSize := 0;
  132.                 while p^ <> 0 do
  133.                     begin
  134.                         resultSize := resultSize + 1;
  135.                         p := Ptr(ord4(p)+1);
  136.                     end;
  137.                 if resultSize < 0 then Fail('Input string size too small!');
  138.                 if HandToHand(resultHand) <> noErr then Fail('HandToHand failed!');
  139.                 SetHandleSize(resultHand,resultSize);
  140.             end
  141.         { On the other hand, if the previous string is empty, make a new, empty one. }
  142.         else
  143.             begin
  144.                 resultHand := NewHandle(0);
  145.                 resultSize := 0;
  146.             end;
  147.  
  148.         { Get our current idea of where the other side's cursor is. }
  149.         col := ThisSPort.currentColumn;
  150.  
  151.         { Figure out when to stop trying (timeout). }
  152.         waitForChars := waitForChars + TickCount;
  153.  
  154.         { Cycle until the timeout happens or we see the termintor character. }
  155.         while true do
  156.             begin
  157.                 { Check if there's any input from the port. }
  158.                 if SerGetBuf(ThisSPort.portInDev,l) <> noErr then disposAndFail('SerGetBuf failed');
  159.                 { If not, do another round or get out, depending on the timeout condition. }
  160.                 if l = 0 then
  161.                     begin
  162.                         if TickCount > waitForChars then leave
  163.                         else cycle;
  164.                     end;
  165.  
  166.                 { Expand the result handle and read in the first character that's waiting. }
  167.                 resultSize := resultSize+1;
  168.                 SetHandleSize(resultHand,resultSize);
  169.                 if MemError <> noErr then disposAndFail('SetHandleSize failed!');
  170.                 HLock(resultHand);
  171.                 l := 1;
  172.                 if FSRead(ThisSPort.portInDev,l,Ptr(ord4(resultHand^)+resultSize-1)) <> noErr then
  173.                     disposAndFail('FSRead failed');
  174.                 HUnlock(resultHand);
  175.  
  176.                 { Strip the character, if appropriate, and then get it into theChar. }
  177.                 p := Ptr(ord4(resultHand^)+resultSize-1);
  178.                 if ThisSPort.stripIncoming then p^ := BAND(p^,$7F);
  179.                 theChar := p^;
  180.  
  181.                 { Weed out control characters, if appropriate. }
  182.                 if ThisSPort.stripControls then
  183.                     if (theChar < space) and (theChar <> tab) and (theChar <> return) and (theChar <> bs) then
  184.                         begin
  185.                             resultSize := resultSize-1;
  186.                             SetHandleSize(resultHand,resultSize);
  187.                             cycle;
  188.                         end;
  189.  
  190.                 { If we're echoing... }
  191.                 if ThisSPort.doEcho then
  192.                     begin
  193.                         { If this is a backspace... }
  194.                         if ThisSPort.doEdit and ((theChar = bs) or (theChar = delete)) then
  195.                             begin
  196.                                 if (col > 1) and (resultSize > 1) then
  197.                                     begin
  198.                                         sendBS;
  199.                                         col := col-1;
  200.                                     end;
  201.                             end
  202.                         { If it's a carriage return... }
  203.                         else if theChar = return then
  204.                             begin
  205.                                 sendCRLF;
  206.                                 col := 1;
  207.                             end
  208.                         { If it's a normal, non-wrapped character... }
  209.                         else if (col < WRAPCOLUMN) or (not ThisSPort.autoWrap) then
  210.                             begin
  211.                                 sendByte(theChar);
  212.                                 col := col+1;
  213.                             end
  214.                         { If it's a space in the wrap column (which only allows spaces)... }
  215.                         else if (theChar = space) and (col = WRAPCOLUMN) then
  216.                             begin
  217.                                 sendByte(space);
  218.                                 col := col+1;
  219.                             end
  220.                         { Otherwise, wrap the last word of the line onto the next line... }
  221.                         else
  222.                             begin
  223.                                 { Figure out how many characters will wrap... }
  224.                                 p := pointer(ord4(resultHand^)+resultSize);
  225.                                 i := 0;
  226.                                 while p <> resultHand^ do
  227.                                     begin
  228.                                         p := pointer(ord4(p)-1);
  229.                                         if (p^ = space) or (p^ = return) then leave;
  230.                                         i := i+1;
  231.                                     end;
  232.                                 { If it's the entire line, forget it. }
  233.                                 if i >= MAXWRAP then i := 1;
  234.                                 { If there's nothing to wrap, then just send a carriage return/linefeed. }
  235.                                 if i = 0 then i := 1
  236.                                 { Otherwise, backspace thru the characters being wrapped, then go to the next
  237.                                     line, then send the wrapping characters. }
  238.                                 else
  239.                                     begin
  240.                                         if i > 1 then for j := 1 to i-1 do sendBS;
  241.                                         sendCRLF;
  242.                                         for j := resultSize-i to resultSize-1 do
  243.                                             sendByte(Ptr(ord4(resultHand^)+j)^);
  244.                                     end;
  245.                                 col := i+1;
  246.                             end;
  247.                     end;
  248.  
  249.                 { If we're editing this line and this is the edit character... }
  250.                 if ThisSPort.doEdit and (theChar = bs) or (theChar = delete) then
  251.                     begin
  252.                         { Eliminate the backspace character. }
  253.                         resultSize := resultSize-1;
  254.                         { If we're allowed to edit it (i.e., it isn't on the previous line on the screen),
  255.                             eliminate the erased character. }
  256.                         if (col >= 1) or (not ThisSPort.doEcho) then resultSize := resultSize-1;
  257.                         { Make sure we're not deleting more than there is. }
  258.                         if resultSize < 0 then resultSize := 0;
  259.                         { Delete it. }
  260.                         SetHandleSize(resultHand,resultSize);
  261.                     end;
  262.                 if lookForTerm and (theChar = termChar) then leave;
  263.                 if resultSize > 30000 then leave;
  264.             end;
  265.  
  266.         { Add in the zero termination for the string. }
  267.         SetHandleSize(resultHand,resultSize+1);
  268.         p := ptr(ord4(resultHand^)+resultSize);
  269.         p^ := 0;
  270.  
  271.         { Return the handle. }
  272.         paramPtr^.returnValue := resultHand;
  273.  
  274.         { Remember where we think the cursor column is. }
  275.         Globals^^.ports[Globals^^.selectedPort].currentColumn := col;
  276.     end;
  277.  
  278. end.
  279.